from SPARQLWrapper import SPARQLWrapper, JSON;

class SubcategoryGrabber():
    sparqlConn = SPARQLWrapper("http://dbpedia.org/sparql");
    def __init__(self):
        self.category = "";
        self.__newcats = set([]);
        self.__categories = set([]);
        self.__supercategory = set([]);
        self.__subcategory = set([]);
    """
    @summary: This is part of SubcategoryGrabbers API. Responsible for running
    """
    
    """
    @summary: The idea of the subcategory tuple:
              (Broader dbPedia Category, Current dbPediaCategory, heterarchy lvl)
    """
    def grab(self, category, maxLvl):
        self.category = category;
        self.__supercategory.add(category);
        currentLvl = 1;
        while(currentLvl != maxLvl):
            supercategory = self.__supercategory.copy();
            subcategory = self.__subcategory.copy();
            for cat in supercategory:
                resultSet = self.__runLocusQuery(cat);
                self.__sortOutCategories(cat, resultSet, currentLvl);
            print("\n");
            for cat in subcategory:
                resultSet = self.__runLocusQuery(cat);
                self.__sortOutCategories(cat, resultSet, currentLvl)            
            currentLvl += 1;
        for tuples in self.__categories:
            print(tuples);
    
    def grabSuper(self, category, maxLvl):
        self.category = category;
        self.__newcats.add(category);
        currentLvl = 1;
        while(currentLvl != maxLvl):
            supercategory = self.__newcats.copy();
            self.__newcats.clear();
            for cat in supercategory:
                resultSet = self.__runSuperQuery(cat);
                for results in resultSet:
                    print (results["broader"]["value"][37:]);
                    self.__newcats.add(results["broader"]["value"][37:]);
                print("\n");
            currentLvl += 1;
            
        
    def equals(self, otherCategory):
        return (self.category == otherCategory);
    
    def __runLocusQuery(self, category):
        #if(self.__notAccountedFor(category)):
        query = self.__buildLocusQuery(category);
        SubcategoryGrabber.sparqlConn.setQuery(query);
        SubcategoryGrabber.sparqlConn.setReturnFormat(JSON);
        resultSet = SubcategoryGrabber.sparqlConn.query().convert();
        return resultSet["results"]["bindings"];
        #return [];
    
    def __runSuperQuery(self, category):
        print(category);
        query = self.__buildSuperQuery(category);
        SubcategoryGrabber.sparqlConn.setQuery(query);
        SubcategoryGrabber.sparqlConn.setReturnFormat(JSON);
        resultSet = SubcategoryGrabber.sparqlConn.query().convert();
        return resultSet["results"]["bindings"];
    
           
    def __sortOutCategories(self, category, resultSet, currentLvl):
        for result in resultSet:  
            if(self.__entryIsCategory(result)):
                catURI = result["s"]["value"];
                if(catURI[37:] == category):
                    #Then we know that we are looking at a supercategory...
                    catURI = result["o"]["value"];
                    superCategory = catURI[37:];
                    if(self.__notAccountedFor(superCategory)):
                        #Then we build the tuple and add it...
                        tuple = superCategory, category, currentLvl;
                        self.__supercategory.add(superCategory);
                        self.__categories.add(tuple);
                else:
                    #It is a subcategory... and we will place it accordingly
                    subCategory = catURI[37:];
                    if(self.__notAccountedFor(subCategory)):
                        tuple = category, subCategory, -currentLvl;
                        self.__subcategory.add(subCategory);
                        self.__categories.add(tuple);
                
    
    def __entryIsCategory(self, result):
        skosLabel = result["p"]["value"][36:];
        return (skosLabel == "broader");
           
    def __notAccountedFor(self, category):
        for tuple in self.__categories:
            if(category in tuple):
                return False;
        return True;
            
    def __buildLocusQuery(self, category):
        query = ("DESCRIBE <http://dbpedia.org/resource/Category:"+ category +">");
        return query;
    
    def __buildSuperQuery(self, category):
        query = ("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
                 "SELECT ?broader "
                 "WHERE { <http://dbpedia.org/resource/Category:"+ category +"> skos:broader ?broader }");
        return query;
    